home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / program / cppnl021.zip / cppnl021.txt next >
Text File  |  1997-03-26  |  12KB  |  392 lines

  1. Issue #021
  2. March, 1997
  3.  
  4.  
  5. Contents:
  6.  
  7. Pointers to Members
  8. A New Angle on Function Pointers
  9. Notes From ANSI/ISO - Clarifications on Exception Handling
  10. Introduction to STL Part 8 - advance() and distance()
  11.  
  12.  
  13. POINTERS TO MEMBERS
  14.  
  15. In ANSI C, function pointers are used like this:
  16.  
  17.         #include <stdio.h>
  18.  
  19.         void f(int i)
  20.         {
  21.                 printf("%d\n", i);
  22.         }
  23.  
  24.         typedef void (*fp)(int);
  25.  
  26.         void main()
  27.         {
  28.                 fp p = &f;
  29.  
  30.                 (*p)(37);       /* these are equivalent */
  31.  
  32.                 p(37);
  33.         }
  34.  
  35. and are employed in a variety of ways, for example to specify a
  36. comparison function to a library function like qsort().
  37.  
  38. In C++, pointers can be similarly used, but there are a couple of
  39. quirks to consider.  We will discuss two of them in this section, and
  40. another one in the next section.
  41.  
  42. The first point to mention is that C++ has C-style functions in it, but
  43. also has other types of functions, notably member functions.  For
  44. example:
  45.  
  46.         class A {
  47.         public:
  48.                 void f(int);
  49.         };
  50.  
  51. In this example, A::f(int) is a member function.  That is, it
  52. operates on object instances of class A, and the function itself has
  53. a "this" pointer that points at the instance in question.
  54.  
  55. Because C++ is a strongly typed language, it is desirable that a
  56. pointer to a member function be treated differently than a pointer to
  57. a C-style function, and that a pointer to a function member of class A
  58. be distinguished from a pointer to a member of class B.  To do this,
  59. we can say:
  60.  
  61.         #include <iostream.h>
  62.  
  63.         class A {
  64.         public:
  65.                 void f(int i) {cout << "value is: " << i << "\n";}
  66.         };
  67.  
  68.         typedef void (A::*pmfA)(int);
  69.  
  70.         pmfA x = &A::f;
  71.  
  72.         void main()
  73.         {
  74.                 A a;
  75.                 A* p = &a;
  76.  
  77.                 (p->*x)(37);
  78.         }
  79.  
  80. Note the notation for actually calling the member function.
  81.  
  82. It is not possible to intermix such a type with other pointer types,
  83. so for example:
  84.  
  85.         void f(int) {}
  86.  
  87.         pmfA x = &f;
  88.  
  89. is invalid.
  90.  
  91. A static member function, as in:
  92.  
  93.         class A {
  94.         public:
  95.                 static void g(int);
  96.         };
  97.  
  98.         typedef void (*fp)(int);
  99.  
  100.         fp p = &A::g;
  101.  
  102. is treated like a C-style function.  A static function has no "this"
  103. pointer and does not operate on actual object instances.
  104.  
  105. Pointers to members are typically implemented just like C function
  106. pointers, but there is an issue with their implementation in cases
  107. where inheritance is used.  In such a case, you have to worry about
  108. computing offsets of subobjects, and so on, when calling a member
  109. function, and for this purpose a runtime structure similar to a
  110. virtual table used for virtual functions is used.
  111.  
  112. It's also possible to have pointers to data members of a class, with
  113. the pointer representing an offset into a class instance.  For example:
  114.  
  115.         #include <iostream.h>
  116.  
  117.         class A {
  118.         public:
  119.                 int x;
  120.         };
  121.  
  122.         typedef int A::*piA;
  123.         piA x = &A::x;
  124.  
  125.         void main()
  126.         {
  127.                 A a;
  128.                 A* p = &a;
  129.  
  130.                 a.x = 37;
  131.  
  132.                 cout << "value is: " << p->*x << "\n";
  133.         }
  134.  
  135. Note that saying "&A::x" does not take the address of an actual data
  136. member in an instance of A, but rather computes a generic offset that
  137. can be applied to any instance.
  138.  
  139.  
  140. A NEW ANGLE ON FUNCTION POINTERS
  141.  
  142. The discussion on function pointers in this issue overlooks one key
  143. angle that has fairly recently been introduced into the language.
  144. This involves distinguishing between C and C++ pointers.  A C-style
  145. pointer in C++, that is, one that does not point to a member function,
  146. is used just like a function pointer in C.  But according to the
  147. standard (section 7.5), such a pointer in fact has a different type.
  148.  
  149. For example, consider:
  150.  
  151.         extern "C" typedef void (*fp1)(int);
  152.  
  153.         extern "C++" typedef void (*fp2)(int);
  154.  
  155.         extern "C" void f(int);
  156.  
  157. fp1 and fp2 are not the same type, and saying:
  158.  
  159.         fp2 p = &f;
  160.  
  161. to initialize p to the f(int) declared in the 'extern "C"' will not
  162. work.
  163.  
  164. It is possible to overload functions on this basis, so that for
  165. example:
  166.  
  167.         extern "C" void f(void (*)(int));
  168.  
  169.         extern "C++" void f(void (*)(int));
  170.  
  171. is legal, with the appropriate f() called based on the function
  172. pointer type passed to it.  The function pointer parameter types in
  173. this example are not identical; the first is a pointer to a C
  174. function, the second a pointer to a C++ one.
  175.  
  176. This feature is new and may not be implemented in your local C++
  177. compiler.
  178.  
  179.  
  180. NOTES FROM ANSI/ISO - CLARIFICATIONS ON EXCEPTION HANDLING
  181. Jonathan Schilling, jls@sco.com
  182.  
  183. The ANSI/ISO C++ standards meeting earlier this month in Nashua, New
  184. Hampshire, produced some clarifications of exception handling
  185. semantics.
  186.  
  187. One interesting case is this one, which was featured in the January
  188. 1997 issue of the magazine C++ Report:
  189.  
  190.         try {
  191.                 // exception prone code here, that may do a throw
  192.         }
  193.         catch (...) {
  194.                 // common error code here
  195.                 
  196.                 try {
  197.                         throw;  // re-throw to more specific handler
  198.                 }
  199.                 catch (ExceptA&) {
  200.                         // handle ExceptA here
  201.                 }
  202.                 catch (ExceptB&) {
  203.                         // handle ExceptB here
  204.                 }
  205.                 catch (...) {
  206.                         // handle unknown exceptions here
  207.                 }
  208.  
  209.                 throw;
  210.         }
  211.  
  212. The idea behind the code is to factor out common error handling logic 
  213. into the first part of the catch handler (so as not to replicate it), 
  214. rethrow the exception to get error handling specific to the exception 
  215. in the individual inner handlers, and then finally to rethrow the 
  216. exception again to let functions further up the call chain do their 
  217. handling.
  218.  
  219. The question is, does this code work as intended?  The draft standard
  220. speaks of a throw creating a temporary object that is then deleted when
  221. the corresponding handler exits.  Does this mean that when the inner
  222. handlers above exit, the rethrow will be of a nonexistent temporary
  223. object?  The standard isn't really clear on this, and some existing 
  224. compilers have been found to do the deletion at the inner handler,
  225. with the result that the program crashes.
  226.  
  227. The answer is that this code should indeed work as intended, and that
  228. the existing compilers for which this does not work are wrong.
  229. (Fortunately SCO's new C++ compiler is one of the ones that is getting
  230. it right!).
  231.  
  232. Furthermore, the committee stated that the value of the standard library 
  233. function uncaught_exception() (see C++ Newsletter #019) changes (from 
  234. false to true) at both of the rethrows, until such time as the rethrown
  235. exception is caught again.
  236.  
  237. Another exception handling issue that was clarified is whether base
  238. class destructors are called when a derived class destructor throws an 
  239. exception:
  240.                 
  241.         class B {
  242.         public:
  243.                 ~B() { ... }
  244.         };
  245.  
  246.         class D : public B {
  247.         public:
  248.                 ~D() { throw "error"; }
  249.         };
  250.  
  251.         void f() {
  252.                 try {
  253.                         D d;
  254.                 }
  255.                 catch (...) { }
  256.         }
  257.  
  258. Does ~B() get called as well as ~D()?  The answer is yes.  This may 
  259. seem almost obvious -- it is part of the general principle of C++
  260. that constructed subobjects always get destroyed if something goes
  261. wrong with the enclosing object -- but in fact there was some debate
  262. on this within the committee.
  263.  
  264. Finally, one of the comments from the ANSI public review period
  265. concerned an area of exception handling that needed no clarification
  266. but is often misunderstood:
  267.  
  268.         try {
  269.                 throw 0;
  270.         }
  271.         catch (void *) {
  272.                 // does the exception get caught here?
  273.         }
  274.  
  275. The handler should not catch the exception, but apparently in some
  276. compilers it does.  The draft standard is clear that throw and catch
  277. types either have to match exactly, or be related by inheritance, or
  278. be subject to a pointer-to-pointer standard conversion.  Since 0 is
  279. not of a pointer type, the last requirement isn't met, and no handler
  280. is found.  Similarly note that the whole range of other standard
  281. conversions do not apply, so that for example a handler of type long
  282. does not catch an exception of type int.
  283.  
  284.  
  285. INTRODUCTION TO STL PART 8 - ADVANCE() AND DISTANCE()
  286.  
  287. In the last issue we started discussing iterators.  They are used in
  288. the Standard Template Library to provide access to the contents of
  289. data structures, and to cycle across multiple data elements.
  290.  
  291. We presented two examples of iterator usage, the first involving
  292. pointers, the second a higher-level construct.  Both of these examples
  293. require some grasp of pointer arithmetic, a daunting subject.  There's
  294. another way to write the example we presented before, using a couple
  295. of STL iterator functions:
  296.  
  297.         #include <algorithm>
  298.         #include <iterator>
  299.         #include <vector>
  300.         #include <iostream>
  301.  
  302.         using namespace std;
  303.  
  304.         const int N = 100;
  305.  
  306.         void main()
  307.         {
  308.                 vector<int> iv(N);
  309.  
  310.                 iv[50] = 37;
  311.                 iv[52] = 47;
  312.  
  313.                 vector<int>::iterator iter = find(iv.begin(), iv.end(), 37);
  314.                 if (iter == iv.end()) {
  315.                         cout << "not found\n";
  316.                 }
  317.                 else {
  318.                         int d = 0;
  319.                         distance(iv.begin(), iter, d);
  320.                         //cout << "found at " << iter - iv.begin() << "\n";
  321.                         cout << "found at " << d << "\n";
  322.                 }
  323.  
  324.                 advance(iter, 2);
  325.                 cout << "value = " << *iter << "\n";
  326.         }
  327.  
  328. The function distance() computes the distance between two iterator
  329. values.  In this example, we know that we're starting at "iv.begin()",
  330. the beginning of the integer vector.  And we've found a match at
  331. "iter", and so we can use distance() to compute the distance between
  332. these, and display this result.  Note that more recently distance()
  333. has been changed to work more like a regular function, with the
  334. beginning and ending arguments supplied and the difference returned as
  335. the result of the function:
  336.  
  337.         d = distance(iv.begin(), iter);
  338.  
  339. A similar issue comes up with advancing an iterator.  For example,
  340. it's possible to use "++" for this, but cumbersome when you wish to
  341. advance the iterator a large value.  Instead of ++, advance() can be
  342. used to advance the iterator a specified number of positions.  In the
  343. example above, we move the iterator forward 2 positions, and then
  344. display the value stored in the vector at that location.
  345.  
  346. These functions provide an alternative way of manipulating iterators,
  347. that does not depend so much on pointer arithmetic.
  348.  
  349.  
  350. ACKNOWLEDGEMENTS
  351.  
  352. Thanks to Nathan Myers, Eric Nagler, David Nelson, and Jonathan
  353. Schilling for help with proofreading.
  354.  
  355.  
  356. SUBSCRIPTION INFORMATION / BACK ISSUES
  357.  
  358. To subscribe to the newsletter, send mail to majordomo@world.std.com
  359. with this line as its message body:
  360.  
  361. subscribe c_plus_plus
  362.  
  363. Back issues are available via FTP from:
  364.  
  365.         rmi.net /pub2/glenm/newslett
  366.  
  367. or on the Web at:
  368.  
  369.         http://rainbow.rmi.net/~glenm
  370.  
  371. There is also a Java newsletter.  To subscribe to it, say:
  372.  
  373. subscribe java_letter
  374.  
  375. using the same majordomo@world.std.com address.
  376.  
  377. -------------------------
  378.  
  379. Copyright (c) 1997 Glen McCluskey.  All Rights Reserved.
  380.  
  381. This newsletter may be further distributed provided that it is copied
  382. in its entirety, including the newsletter number at the top and the
  383. copyright and contact information at the bottom.
  384.  
  385. Glen McCluskey & Associates
  386. Professional C++ Consulting
  387. Internet: glenm@glenmccl.com
  388. Phone: (800) 722-1613 or (970) 490-2462
  389. Fax: (970) 490-2463
  390. FTP: rmi.net /pub2/glenm/newslett (for back issues)
  391. Web: http://rainbow.rmi.net/~glenm
  392.